package com.eneat.smartrule.service.Impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.eneat.smartrule.dto.request.RuleExecuteRequest;
import com.eneat.smartrule.dto.request.RuleReq;
import com.eneat.smartrule.dto.response.PageResponse;
import com.eneat.smartrule.dto.response.RuleRes;
import com.eneat.smartrule.mapper.RuleConditionMapper;
import com.eneat.smartrule.mapper.RuleExecutionRecordMapper;
import com.eneat.smartrule.mapper.RuleMapper;
import com.eneat.smartrule.model.Rule;
import com.eneat.smartrule.model.RuleCondition;
import com.eneat.smartrule.repository.RuleConditionRepo;
import com.eneat.smartrule.repository.RuleExecutionRecordRepo;
import com.eneat.smartrule.repository.RuleRepo;
import com.eneat.smartrule.restAPI.ErrorEnum;
import com.eneat.smartrule.restAPI.ServiceException;
import com.eneat.smartrule.service.RuleService;
import com.eneat.smartrule.util.ExpressionUtil;
import com.googlecode.aviator.AviatorEvaluator;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

@Service
public class RuleServiceImpl extends ServiceImpl<RuleMapper, Rule> implements RuleService {

    @Autowired
    private RuleMapper mapper;

    @Autowired
    private RuleConditionServiceImpl ruleConditionService;

    @Autowired
    private RuleConditionMapper ruleConditionMapper;


    @Autowired
    private RuleExecutionRecordMapper ruleExecutionRecordMapper;

    @Autowired
    private RuleExecutionRecordRepo  ruleExecutionRecordRepo;

    @Autowired
    private RuleConditionRepo ruleConditionRepo;

    @Autowired
    private RuleRepo ruleRepo;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createRule(Rule rule) {
        String expressionStr = ExpressionUtil.buildExpression(rule.getRuleConditions());
        //校验expressionStr是否合法。
        rule.setExpression(expressionStr);
        this.save(rule);
        ruleConditionRepo.save(rule.getRuleConditions(), rule.getId(), null);
    }



    @Override
    public RuleRes getRuleById(Integer id) {
        Rule rule = mapper.selectById(id);
        if (rule == null) {
            return null;
        }
        RuleRes ruleRes = new RuleRes();
        BeanUtils.copyProperties(rule, ruleRes);
        ruleRes.setRuleConditions(ruleConditionRepo.findByRuleId(rule.getId()));
        return ruleRes;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean updateRule( Rule rule) {
        if (rule.getId() == null) {
            throw new ServiceException(ErrorEnum.PARAM_ERROR, "规则ID不能为空");
        }
        String expressionStr = ExpressionUtil.buildExpression(rule.getRuleConditions());
        rule.setExpression(expressionStr);
        mapper.updateById(rule);
        ruleConditionMapper.delete(new LambdaQueryWrapper<RuleCondition>().eq(RuleCondition::getRuleId, rule.getId()));
        ruleConditionRepo.save(rule.getRuleConditions(), rule.getId(), null);
        return true;
    }

    @Override
    public boolean deleteRule(Integer id) {
        mapper.deleteById(id);
        ruleConditionMapper.delete(new LambdaQueryWrapper<RuleCondition>().eq(RuleCondition::getRuleId, id));
        return true;
    }


    @Override
    public PageResponse<RuleRes> searchRules(RuleReq ruleReq) {
      return ruleRepo.searchRules(ruleReq);
    }

    /**
     * 执行指定规则并返回执行结果。
     * <p>
     * 该方法会根据传入的规则ID获取规则详情，校验输入参数是否完整，
     * 使用 Aviator 表达式引擎执行规则表达式，并将执行记录保存至数据库。
     *
     * @param ruleExecuteRequest 包含规则ID和执行所需参数的请求对象
     * @return 规则表达式的执行结果（通常是 Boolean 或数值类型）
     * @throws ServiceException 如果参数缺失或数量不匹配时抛出异常
     */
    @Override
    public Object execute(RuleExecuteRequest ruleExecuteRequest) {
        RuleRes ruleById = this.getRuleById(ruleExecuteRequest.getRuleId());
        //校验参数是否对。
        //获取所有的fieldName
        ArrayList<String> fieldNames = new ArrayList<>();
        getAllFieldName(ruleById.getRuleConditions(),fieldNames);
        if(ruleExecuteRequest.getParameters().size()!=fieldNames.size()){
            throw new ServiceException(ErrorEnum.PARAM_ERROR, "参数数量不对");
        }
        fieldNames.forEach(fieldName -> {
            if(!ruleExecuteRequest.getParameters().containsKey(fieldName)){
                throw new ServiceException(ErrorEnum.PARAM_ERROR,"缺少"+fieldName+"参数");
            }
        });
        Object execute = AviatorEvaluator.execute(ruleById.getExpression(), ruleExecuteRequest.getParameters());
        Rule rule = new Rule();
        BeanUtils.copyProperties(ruleById,rule);
        ruleExecutionRecordRepo.saveExecutionRecord(rule,execute,ruleExecuteRequest.getParameters());
        return execute;
    }



    /**
     * 递归提取规则条件及其子条件中的所有字段名（field）
     * <p>
     * 用于在执行规则前校验输入参数是否完整：
     * 遍历规则的所有条件（包括嵌套的 subRuleConditions），
     * 收集其中使用的字段名（field），以便后续与传入的参数进行比对。
     *
     * @param conditions 规则条件列表，可能包含嵌套的子条件
     * @param fieldNames 用于收集提取出的字段名的输出列表
     */
    public void getAllFieldName(List<RuleCondition> conditions, List<String> fieldNames){
        for(RuleCondition condition : conditions){
            fieldNames.add(condition.getField());
            if(condition.getSubRuleConditions() != null && !condition.getSubRuleConditions().isEmpty()){
                getAllFieldName(condition.getSubRuleConditions(), fieldNames);
            }
        }


    }
}
